#include <stdio.h>
#include <stdlib.h>
#include <GL/glx.h> // This includes the necessary X headers
//#include <GL/gl.h>
//#include <GL/glu.h>
#include "debug.h"
#include "sprite.h"
#include "callback.h"
#include "input.h"
#include "opengl.h"
#include "thread.h"
#include "linux.h"

//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
Display *display = NULL;
Window   window;

static sprite_t *spr;
static char *spr_filename;
static void linux_opengl_thread();
static void close_linux_opengl();
static int running = 0;

void init_linux_graphics(){
    running = 0;
    create_and_run_thread((void*)&linux_opengl_thread, NULL, (void*)&close_linux_graphics);
    //Wait until the graphics thread is ready for processing...
    while(!running){
        thread_yield();
    }
}

#define IMAGE_BUFFER_LENGTH (1)

static void linux_opengl_thread(){
    XEvent event;
    XSetWindowAttributes windowAttributes;
    XVisualInfo *visualInfo = NULL;
    Colormap colorMap;
    GLXContext glxContext;
    int errorBase, eventBase;

    spr = NULL;
    spr_filename = NULL;
    // Open a connection to the X server
    display = XOpenDisplay( NULL );

    if(display == NULL ){
        dbg_msga("glxsimple: %s\n", "could not open display");
        exit(1);
    }

    // Make sure OpenGL's GLX extension supported
    if(!glXQueryExtension(display, &errorBase, &eventBase)){
        dbg_msga("glxsimple: %s\n", "X server has no OpenGL GLX extension");
        exit(1);
    }

    // Find an appropriate visual

    int doubleBufferVisual[]  ={
        GLX_RGBA,           // Needs to support OpenGL
        GLX_DEPTH_SIZE, 16, // Needs to support a 16 bit depth buffer
        GLX_DOUBLEBUFFER,   // Needs to support double-buffering
        None                // end of list
    };

    int singleBufferVisual[] ={
        GLX_RGBA,           // Needs to support OpenGL
        GLX_DEPTH_SIZE, 16, // Needs to support a 16 bit depth buffer
        None                // end of list
    };

    //printf("%ld\n", DefaultScreen(display));
    //printf("%ld\n", doubleBufferVisual);
    // Try for the double-bufferd visual first
    visualInfo = glXChooseVisual(display, DefaultScreen(display), doubleBufferVisual);

    if( visualInfo == NULL ){
    	// If we can't find a double-bufferd visual, try for a single-buffered visual...
        visualInfo = glXChooseVisual(display, DefaultScreen(display), singleBufferVisual);

        if(visualInfo == NULL){
            dbg_msga("glxsimple: %s\n", "no RGB visual with depth buffer");
            exit(1);
        }

    }

    // Create an OpenGL rendering context
    glxContext = glXCreateContext( display, 
                                   visualInfo, 
                                   NULL,      // No sharing of display lists
                                   GL_TRUE ); // Direct rendering if possible
                           
    if( glxContext == NULL ){
        fprintf(stderr, "glxsimple: %s\n", "could not create rendering context");
        exit(1);
    }

    // Create an X colormap since we're probably not using the default visual 
    colorMap = XCreateColormap(display, 
                                RootWindow(display, visualInfo->screen), 
                                visualInfo->visual, 
                                AllocNone );

    windowAttributes.colormap     = colorMap;
    windowAttributes.border_pixel = 0;
    windowAttributes.event_mask   = ExposureMask           |
                                    VisibilityChangeMask   |
                                    KeyPressMask           |
                                    KeyReleaseMask         |
                                    ButtonPressMask        |
                                    ButtonReleaseMask      |
                                    PointerMotionMask      |
                                    StructureNotifyMask    |
                                    SubstructureNotifyMask |
                                    FocusChangeMask;
    
    // Create an X window with the selected visual
    window = XCreateWindow(display, 
                             RootWindow(display, visualInfo->screen), 
                             0, 0,     // x/y position of top-left outside corner of the window
                             800, 600, // Width and height of window
                             0,        // Border width
                             visualInfo->depth,
                             InputOutput,
                             visualInfo->visual,
                             CWBorderPixel | CWColormap | CWEventMask,
                             &windowAttributes );

    XSetStandardProperties(display,
                           window,
                           "somlg",
                           "somlg",
                           None,
                           NULL,
                           0,
                           NULL);

    // Bind the rendering context to the window
    glXMakeCurrent(display, window, glxContext);

    // Request the X window to be displayed on the screen
    XMapWindow(display, window);

    // Init OpenGL...
    init_opengl();


    //Signal the main thread that the graphics system is ready to go.
    running = 1;

    //
    // Enter the render loop and don't forget to dispatch X events as
    // they occur.
    //
    while(running){
        if(spr != NULL && spr_filename != NULL){
            load_png(spr_filename, spr);
            spr_filename = NULL;
            //spr = NULL;
        }

        while(XPending(display)){ // Loop to compress events
            XNextEvent(display, &event);

            switch(event.type){
                case ButtonPress:
                    mousepress(event.xbutton.button);
            	    if(event.xbutton.button == 1){
						//g_nLastMousePositX = event.xmotion.x;
				        //g_nLastMousePositY = event.xmotion.y;
						//g_bMousing = true;
					}
                break;

                case ButtonRelease:
                    mouserelease(event.xbutton.button);
                	//if( event.xbutton.button == 1 )
                		//g_bMousing = false;
                break;
                
                case KeyPress:
                    keyboardpress(event.xkey.keycode);
                    //exit(1);
                break;

                case KeyRelease:
                    keyboardrelease(event.xkey.keycode);
                break;

                case MotionNotify:
                    //if( g_bMousing )
                    //{
	                    //g_fSpinX -= (event.xmotion.x - g_nLastMousePositX);
						//g_fSpinY -= (event.xmotion.y - g_nLastMousePositY);
					
						//g_nLastMousePositX = event.xmotion.x;
					    //g_nLastMousePositY = event.xmotion.y;
                    //}
                break;

                case Expose:
                    fprintf( stderr, "Expose event\n" );
                break;

                case ConfigureNotify:
                    glViewport(0, 0, event.xconfigure.width, event.xconfigure.height );
                    break;
            }

        }
        graphics_callback();
        render_gui();

    //while(XPending(display)); // Loop to compress events
    }
    XUnmapWindow(display, window);
    XDestroyWindow(display, window);
    XCloseDisplay(display);
    display = NULL;
}

void close_linux_graphics(){
    running = 0;
    while(display){
        thread_yield();
    }
}

int test(int argc, char **argv){
    init_linux_graphics();

    spr = crt_spr();
    spr_filename = "images/sladsbed.png";
    //image_buffer = get_image_buffer();
    //load_png("images/sladsbed.png", spr);

    return 0;
}
